﻿using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

namespace ChangDiTools
{
    public static class EntTools
    {
        public static void Move(this ObjectId id, Point3d souresPoint3D, Point3d targetPoint3D)
        {
            Vector3d vector = targetPoint3D.GetVectorTo(souresPoint3D); //创建向量
            Matrix3d mt = Matrix3d.Displacement(vector); //构建用于移动实体的矩阵
            Entity ent = id.GetObject(OpenMode.ForWrite) as Entity; //图形对象必须在写的状态下才能被平移
            //必须保证objectID所在的数据库开启了事务处理，否则会造成AutoCAD的崩溃
            ent.TransformBy(mt);
            ent.DowngradeOpen();
        }

        public static void Move(this Entity ent, Point3d souresPoint3D, Point3d targetPoint3D)
        {
            if (ent.IsNewObject)
            {
                //如果是还未被添加到数据库中的新实体
                Vector3d vector = targetPoint3D.GetVectorTo(souresPoint3D); //创建向量
                Matrix3d mt = Matrix3d.Displacement(vector); //构建用于移动实体的矩阵
                ent.TransformBy(mt);
            }
            else //如果是已经添加到数据库中的实体
            {
                ent.ObjectId.Move(souresPoint3D, targetPoint3D);
            }
        }

        public static ObjectId Copy(this ObjectId id, Point3d souresPoint3D, Point3d targetPoint3D)
        {
            Vector3d vector = targetPoint3D.GetVectorTo(souresPoint3D); //创建向量
            Matrix3d mt = Matrix3d.Displacement(vector); //构建用于复制实体的矩阵
            Entity ent = id.GetObject(OpenMode.ForWrite) as Entity; //图形对象必须在写的状态下才能被平移
            Entity entCopy = ent.GetTransformedCopy(mt);
            //必须保证objectID所在的数据库开启了事务处理，否则会造成AutoCAD的崩溃
            ObjectId copyId = id.Database.AddEntity(entCopy);
            return copyId;
        }

        public static ObjectId Copy(this Entity ent, Point3d souresPoint3D, Point3d targetPoint3D)
        {
            if (ent.IsNewObject)
            {
                //如果是还未被添加到数据库中的新实体
                Vector3d vector = targetPoint3D.GetVectorTo(souresPoint3D); //创建向量
                Matrix3d mt = Matrix3d.Displacement(vector); //构建用于复制实体的矩阵
                Entity entCopy = ent.GetTransformedCopy(mt);
                //必须保证objectID所在的数据库开启了事务处理，否则会造成AutoCAD的崩溃
                ObjectId copyId = ent.Database.AddEntity(entCopy);
                return copyId;

            }
            else //如果是已经添加到数据库中的实体
            {
                return ent.ObjectId.Copy(souresPoint3D, targetPoint3D);
            }
        }

        public static void Rotate(this ObjectId id, Point3d basePoint3D, double angle) {
            Matrix3d mt = Matrix3d.Rotation(angle, Vector3d.ZAxis, basePoint3D); //构建用于旋转实体的矩阵
            Entity ent = id.GetObject(OpenMode.ForWrite) as Entity; //图形对象必须在写的状态下才能被平移
            //必须保证objectID所在的数据库开启了事务处理，否则会造成AutoCAD的崩溃
            ent.TransformBy(mt);
            ent.DowngradeOpen();
        }

        public static void Rotate(this Entity ent, Point3d basePoint3D, double angle) {
            if (ent.IsNewObject) {
                //如果是还未被添加到数据库中的新实体
                Matrix3d mt = Matrix3d.Rotation(angle, Vector3d.ZAxis, basePoint3D); //构建用于旋转实体的矩阵
                ent.TransformBy(mt);
            }
            else //如果是已经添加到数据库中的实体
            {
                ent.ObjectId.Rotate(basePoint3D, angle);

            }
        }
        public static void Scale(this ObjectId id, Point3d basePoint3D, double sacleFactor) {
            Matrix3d mt = Matrix3d.Scaling(sacleFactor,  basePoint3D); //构建用于缩放实体的矩阵
            Entity ent = id.GetObject(OpenMode.ForWrite) as Entity; //图形对象必须在写的状态下才能被平移
            //必须保证objectID所在的数据库开启了事务处理，否则会造成AutoCAD的崩溃
            ent.TransformBy(mt);
            ent.DowngradeOpen();
        }

        public static void Scale(this Entity ent, Point3d basePoint3D, double sacleFactor) {
            if (ent.IsNewObject) {
                //如果是还未被添加到数据库中的新实体
                Matrix3d mt = Matrix3d.Scaling(sacleFactor, basePoint3D); //构建用于缩放实体的矩阵
                ent.TransformBy(mt);
            }
            else //如果是已经添加到数据库中的实体
            {
                ent.ObjectId.Scale(basePoint3D, sacleFactor);

            }
        }
        public static ObjectId Mirror(this ObjectId id, Point3d pt1, Point3d pt2,bool eraseSourceObject) {
            Line3d miLine3D=new Line3d(pt1,pt2);
            Matrix3d mt = Matrix3d.Mirroring(miLine3D); //构建用于复制实体的矩阵
            Entity ent = id.GetObject(OpenMode.ForWrite) as Entity; //图形对象必须在写的状态下才能被平移
            if (eraseSourceObject)
            {
                ent.TransformBy(mt);
            }
            else {
                Entity entCopy = ent.GetTransformedCopy(mt);
                id = id.Database.AddEntity(entCopy);
            }
            return id;
        }

        public static ObjectId Mirror(this Entity ent, Point3d pt1, Point3d pt2, bool eraseSourceObject) {
            if (ent.IsNewObject) {
                Line3d miLine3D = new Line3d(pt1, pt2);
                ObjectId id = ent.Id;
                Matrix3d mt = Matrix3d.Mirroring(miLine3D); //构建用于复制实体的矩阵
                if (eraseSourceObject) {
                    ent.TransformBy(mt);
                }
                else {
                    Entity entCopy = ent.GetTransformedCopy(mt);
                    id = id.Database.AddEntity(entCopy);
                }
                return id;

            }
            else //如果是已经添加到数据库中的实体
            {
                return ent.ObjectId.Mirror(pt1, pt2, eraseSourceObject);
            }
        }

        public static ObjectIdCollection Offset(this ObjectId id, double dis) {
            ObjectIdCollection ids = new ObjectIdCollection();
            Curve curve = id.GetObject(OpenMode.ForWrite) as Curve;
            if (curve != null) {
                try {
                    DBObjectCollection offsetCurves = curve.GetOffsetCurves(dis);
                    Entity[] offsetEntities = new Entity[offsetCurves.Count];
                    offsetCurves.CopyTo(offsetEntities, 0);
                    ids = id.Database.AddEntity(offsetEntities);
                }
                catch {
                    Application.ShowAlertDialog("无法偏移！");
                }
            }
            else {
                Application.ShowAlertDialog("无法偏移！");
            }
            return ids;
        }
        public static DBObjectCollection Offset(this Entity ent, double dis) {
            DBObjectCollection offsetCurves = new DBObjectCollection();
            Curve curve = ent as Curve;
            if (curve != null) {
                try {
                    offsetCurves = curve.GetOffsetCurves(dis);
                    Entity[] offsetEnts = new Entity[offsetCurves.Count];
                    offsetCurves.CopyTo(offsetEnts, 0);
                }
                catch {
                    Application.ShowAlertDialog("无法偏移！");
                }
            }
            else {
                Application.ShowAlertDialog("无法偏移！");
            }
            return offsetCurves;
        }

        public static ObjectIdCollection ArrayRectang(this ObjectId id, int numRows, int numCols, double disRows, double disCols) {
            // 用于返回阵列后的实体集合的ObjectId
            ObjectIdCollection ids = new ObjectIdCollection();
            // 以读的方式打开实体
            Entity ent = (Entity)id.GetObject(OpenMode.ForRead);
            for (int m = 0; m < numRows; m++) {
                for (int n = 0; n < numCols; n++) {
                    // 获取平移矩阵
                    Matrix3d mt = Matrix3d.Displacement(new Vector3d(n * disCols, m * disRows, 0));
                    Entity entCopy = ent.GetTransformedCopy(mt);// 复制实体
                    // 将复制的实体添加到模型空间
                    ObjectId entCopyId = id.Database.AddEntity(entCopy);
                    ids.Add(entCopyId);// 将复制实体的ObjectId添加到集合中
                }
            }
            ent.UpgradeOpen();// 切换实体为写的状态
            ent.Erase();// 删除实体
            return ids;// 返回阵列后的实体集合的ObjectId
        }

        /// <summary>
        /// 环形阵列实体
        /// </summary>
        /// <param name="id">实体的ObjectId</param>
        /// <param name="cenPt">环形阵列的中心点</param>
        /// <param name="numObj">在环形阵列中所要创建的对象数量</param>
        /// <param name="angle">以弧度表示的填充角度，正值表示逆时针方向旋转，负值表示顺时针方向旋转，如果角度为0则出错</param>
        /// <returns>返回阵列后的实体集合的ObjectId</returns>
        public static ObjectIdCollection ArrayPolar(this ObjectId id, Point3d cenPt, int numObj, double angle) {
            ObjectIdCollection ids = new ObjectIdCollection();
            Entity ent = (Entity)id.GetObject(OpenMode.ForRead);
            for (int i = 0; i < numObj - 1; i++) {
                Matrix3d mt = Matrix3d.Rotation(angle * (i + 1) / numObj, Vector3d.ZAxis, cenPt);
                Entity entCopy = ent.GetTransformedCopy(mt);
                ObjectId entCopyId = id.Database.AddEntity(entCopy);
                ids.Add(entCopyId);
            }
            return ids;
        }

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="id">实体的ObjectId</param>
        public static void Erase(this ObjectId id) {
            DBObject ent = id.GetObject(OpenMode.ForWrite);
            ent.Erase();
        }

        /// <summary>
        /// 计算图形数据库模型空间中所有实体的包围框
        /// </summary>
        /// <param name="db">数据库对象</param>
        /// <returns>返回模型空间中所有实体的包围框</returns>
        public static Extents3d GetAllEntsExtent(this Database db) {
            Extents3d totalExt = new Extents3d();
            using (Transaction trans = db.TransactionManager.StartTransaction()) {
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btRcd = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
                foreach (ObjectId entId in btRcd) {
                    Entity ent = trans.GetObject(entId, OpenMode.ForRead) as Entity;
                    totalExt.AddExtents(ent.GeometricExtents);
                }
            }
            return totalExt;
        }
        
    }

    public static class CircleTools
    {
        /// <summary>
        /// 两点创建园
        /// </summary>
        /// <param name="circle">园对象</param>
        /// <param name="startPoint3D">起点</param>
        /// <param name="endPoint3D">终点</param>
        public static void CreatCircle(this Circle circle, Point3d startPoint3D, Point3d endPoint3D) {
            circle.Center = Tools.MidPoints(startPoint3D, endPoint3D);
            circle.Radius = startPoint3D.DistanceTo(endPoint3D) / 2;
        }
        /// <summary>
        /// 三点法创建圆
        /// </summary>
        /// <param name="circle">圆对象</param>
        /// <param name="pt1">第一点</param>
        /// <param name="pt2">第二点</param>
        /// <param name="pt3">第三点</param>
        /// <returns>若成功创建圆，则返回true，否则返回false</returns>
        public static bool CreatCircle(this Circle circle, Point3d pt1, Point3d pt2, Point3d pt3) {
            Vector3d va = pt1.GetVectorTo(pt2);
            Vector3d vb = pt1.GetVectorTo(pt3);
            //如两矢量夹角为0或180度（π弧度),则三点共线.
            if (va.GetAngleTo(vb) % Math.PI == 0) {
                return false;
            }
            else {
                CircularArc3d geArc = new CircularArc3d(pt1, pt2, pt3);//给对象只能用来计算，不能再图形窗口中显示
                circle.Center = geArc.Center;
                circle.Radius = geArc.Radius;
                return true;
            }
        }
    }

    public static class ArcTools
    {
        /// <summary>
        /// 根据圆心、起点、终点创建圆弧
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="startPoint3D"></param>
        /// <param name="centerPoint3D"></param>
        /// <param name="endPoint3D"></param>
        public static void CreateArcSCE(this Arc arc,Point3d startPoint3D,Point3d centerPoint3D,Point3d endPoint3D)
        {
            arc.Center = centerPoint3D;
            arc.Radius = centerPoint3D.DistanceTo(startPoint3D);
            Vector2d startVector2D=new Vector2d(startPoint3D.X-centerPoint3D.X,startPoint3D.Y-centerPoint3D.Y);
            Vector2d endVector2D=new Vector2d(endPoint3D.X-centerPoint3D.X,endPoint3D.Y-centerPoint3D.Y);
            arc.StartAngle = startVector2D.Angle;
            arc.EndAngle = endVector2D.Angle;
        }
        /// <summary>
        /// 根据起点、圆心和圆弧角度创建圆弧
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="startPoint3D"></param>
        /// <param name="centerPoint3D"></param>
        /// <param name="angle"></param>
        public static void CreateArc(this Arc arc,Point3d startPoint3D,Point3d centerPoint3D,double angle)
        {
            arc.Center = centerPoint3D;
            arc.Radius = centerPoint3D.DistanceTo(startPoint3D);
            Vector2d startVector2D=new Vector2d(startPoint3D.X-centerPoint3D.X,startPoint3D.Y-centerPoint3D.Y);
            arc.StartAngle = startVector2D.Angle;
            arc.EndAngle = startVector2D.Angle+angle;
        }

        /// <summary>
        /// 三点法创建圆弧
        /// </summary>
        /// <param name="arc">圆弧对象</param>
        /// <param name="startPoint">起点</param>
        /// <param name="pointOnArc">圆弧上的点</param>
        /// <param name="endPoint">终点</param>
        public static bool CreatArc(this Arc arc, Point3d startpoint, Point3d pointOnArc, Point3d endPoint) {
            Vector3d va = startpoint.GetVectorTo(pointOnArc);
            Vector3d vb = startpoint.GetVectorTo(endPoint);
            //如两矢量夹角为0或180度（π弧度),则三点共线.
            if (va.GetAngleTo(vb) % Math.PI == 0) {
                return false;
            }
            else {
                CircularArc3d geArc = new CircularArc3d(startpoint, pointOnArc, endPoint);//给对象只能用来计算，不能再图形窗口中显示
                arc.Center = geArc.Center;
                arc.Radius = geArc.Radius;
                arc.StartAngle = (new Line(arc.Center, startpoint).Angle);
                arc.EndAngle = (new Line(arc.Center, endPoint).Angle);
                return true;
            }
        }
    }
}
